package com.ai.service.made.impl;

import com.ai.common.CommonResponse;
import com.ai.common.constant.HttpConstant;
import com.ai.common.constant.enumP.AlgorithmStateEnums;
import com.ai.common.constant.enumP.AvailableEnums;
import com.ai.common.constant.enumP.SwitchUrlType;
import com.ai.entity.alarm.SwitchAlgorithmParam;
import com.ai.entity.function.FunctionPO;
import com.ai.entity.made.AlgorithmPackageStatus;
import com.ai.entity.made.AlgorithmServerRelation;
import com.ai.entity.made.AlgorithmServerRelationVo;
import com.ai.entity.made.page.AlgorithmPackagePage;
import com.ai.entity.server.ServerPO;
import com.ai.mapper.made.AlgorithmPackageStatusMapper;
import com.ai.model.param.AlgorithmPackageParam;
import com.ai.model.param.DeployAlgorithmParam;
import com.ai.service.made.FunctionService;
import com.ai.service.made.IAlgorithmPackageStatusService;
import com.ai.service.made.IAlgorithmServerRelationService;
import com.ai.service.made.ServerService;
import com.ai.util.FileUploaderUtil;
import com.ai.util.HttpRequestUtil;
import com.ai.util.SecurityUtils;
import com.ai.util.SftpFileUploaderUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.security.auth.callback.Callback;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author jiaok
 * @since 2024-08-12
 */
@Service
@Slf4j
public class AlgorithmPackageStatusServiceImpl extends ServiceImpl<AlgorithmPackageStatusMapper, AlgorithmPackageStatus> implements IAlgorithmPackageStatusService {

    @Value("${api.switchAlgorithm.port}")
    private String switchAlgorithmPort;

    @Value("${api.switchAlgorithm.startPath}")
    private String switchAlgorithmStartPath;

    @Value("${api.switchAlgorithm.statusPath}")
    private String switchAlgorithmStatusPath;

    @Value("${api.switchAlgorithm.stopPath}")
    private String switchAlgorithmStopPath;
    @Resource
    private FileUploaderUtil fileUploaderUtil;

    @Resource
    private ServerService serverService;


    @Resource
    private FunctionService functionService;


    @Resource
    private IAlgorithmServerRelationService iAlgorithmServerRelationService;


    @Transactional
    @Override
    public CommonResponse uploadAlgorithm(MultipartFile file, AlgorithmPackageParam algorithmPackageParam) {

        //新增算法包上传记录

        //上传文件
        String algorithmFilePath = fileUploaderUtil.uploadAlgorithmFile(file, algorithmPackageParam);
        if (algorithmFilePath == null) {
            throw new RuntimeException("文件上传异常");
        }
        //获取DTO
        AlgorithmPackageStatus algorithmPackageStatus = convertToAlgorithmDTO(algorithmPackageParam, algorithmFilePath);
        algorithmPackageStatus.setFunctionId(algorithmPackageParam.getAlgorithmId());
        save(algorithmPackageStatus);

        return CommonResponse.ok("算法上传成功");
    }


    @Override
    public CommonResponse getServerList() {
        List<ServerPO> serverPOS = serverService.getServerList();
        return CommonResponse.ok(serverPOS);
    }

    @Override
    public CommonResponse getVersionList(String algorithmId) {

        List<AlgorithmPackageStatus> packageStatusList = list(new QueryWrapper<AlgorithmPackageStatus>().eq("function_id", algorithmId));

        return CommonResponse.ok(packageStatusList);
    }

    @Override
    @Transactional
    public CommonResponse deployAlgorithm(DeployAlgorithmParam deployAlgorithmParam) {

        //查看该功能是否正在目标服务器上部署运行
        iAlgorithmServerRelationService.isDeployedAndRunning(deployAlgorithmParam);
        //获取服务器信息
        ServerPO serverPO = serverService.getById(deployAlgorithmParam.getServerId());
        //获取算法信息
        AlgorithmPackageStatus algorithmPackageStatus = getById(deployAlgorithmParam.getAlgorithmId());

        FunctionPO functionPO = functionService.getById(algorithmPackageStatus.getFunctionId());

        SftpFileUploaderUtil sftpFileUploaderUtil =
                new SftpFileUploaderUtil().setHost(serverPO.getIp())
                        .setUsername(serverPO.getUsername())
                        .setPassword(serverPO.getPassword())
                        .setRemoteDirectory(serverPO.getDeployPath())
                        .setRemoteDirectory(serverPO.getDeployPath()+"/"+functionPO.getType()+"/"+algorithmPackageStatus.getVersion());

        String algorithmFilePath = sftpFileUploaderUtil.uploadFile(algorithmPackageStatus.getPackagePath());

        //保存部署关系
        iAlgorithmServerRelationService.saveRelation(deployAlgorithmParam,algorithmFilePath);


        return CommonResponse.ok("部署完成");
    }

    @Override
    public CommonResponse getRevisionHistory(AlgorithmPackagePage algorithmPackagePage) {

        QueryWrapper<AlgorithmPackageStatus> statusQueryWrapper = new QueryWrapper<>();
        statusQueryWrapper.orderByDesc("version");
        QueryWrapper<AlgorithmPackageStatus> queryWrapper = algorithmPackagePage.getQuery(statusQueryWrapper);
        AlgorithmPackagePage page = page(algorithmPackagePage, queryWrapper);

        return CommonResponse.ok(page);
    }

    @Override
    public CommonResponse getDeployRelationList(String functionId) {

       List<AlgorithmServerRelation> algorithmServerRelations= iAlgorithmServerRelationService.getDeployRelationList(functionId);

        ArrayList<AlgorithmServerRelationVo> res = new ArrayList<>();


        algorithmServerRelations.forEach(item ->{
           ServerPO serverPO = serverService.getById(item.getServerId());
           AlgorithmPackageStatus packageStatus = getById(item.getAlgorithmId());

           AlgorithmServerRelationVo algorithmServerRelationVo = new AlgorithmServerRelationVo();
           BeanUtils.copyProperties(item,algorithmServerRelationVo);
           algorithmServerRelationVo.setServerName(serverPO.getNickname());
           algorithmServerRelationVo.setAlgorithmComment(packageStatus.getComment());
           res.add(algorithmServerRelationVo);
       });

       return CommonResponse.ok("查询成功",res);

    }

    @Override
    public CommonResponse switchAlgorithm(String relationId,String switchStatus) {

        String  runningState = "";

        AlgorithmServerRelation algorithmServerRelation = iAlgorithmServerRelationService.getById(relationId);
        String algorithmFilePath = algorithmServerRelation.getAlgorithmFilePath()+"/";
        ServerPO serverPO = serverService.getById(algorithmServerRelation.getServerId());
        AlgorithmPackageStatus packageStatus = getById(algorithmServerRelation.getAlgorithmId());
        //算法启动环境
        String algorithmEnv = packageStatus.getBck1();
        //算法启动文件
        String algorithmFile = packageStatus.getBck2();

        String weights = packageStatus.getBck3();

        FunctionPO functionPO = functionService.getById(algorithmServerRelation.getFunctionId());

        SwitchAlgorithmParam switchAlgorithmParam = new SwitchAlgorithmParam();
        switchAlgorithmParam.setAlgorithmEnv(algorithmEnv);
        switchAlgorithmParam.setAlgorithmFile(algorithmFile);
        switchAlgorithmParam.setWeights(weights);
        switchAlgorithmParam.setAlgorithmType(String.valueOf(functionPO.getType()));
        switchAlgorithmParam.setAlgorithmPath(algorithmFilePath);

        String switchUrl = "";
        if (SwitchUrlType.OPEN.getType().equals(switchStatus)){
            switchUrl = HttpConstant.HTTP_REQUEST_PREFIX + serverPO.getIp() +":"+ switchAlgorithmPort +  switchAlgorithmStartPath;
            runningState=AlgorithmStateEnums.START.getType();
        }else if (SwitchUrlType.CLOSE.getType().equals(switchStatus)){
            switchUrl = HttpConstant.HTTP_REQUEST_PREFIX + serverPO.getIp() +":"+ switchAlgorithmPort +  switchAlgorithmStopPath ;
            runningState=AlgorithmStateEnums.NOT_START.getType();
        }else {
            //查询状态，无需修改运行状态
            switchUrl = HttpConstant.HTTP_REQUEST_PREFIX + serverPO.getIp() +":"+ switchAlgorithmPort +  switchAlgorithmStatusPath;
        }

        String param = JSONObject.toJSONString(switchAlgorithmParam);
        log.info("===========================  请求算法路径：{}  ===========================",switchUrl);
        log.info("===========================  请求入参：{} ===========================",param);
        String res = HttpRequestUtil.sendPost(switchUrl, param);
        if (StringUtils.isBlank(res)){
            return CommonResponse.error("网络请求失败！");
        }
        JSONObject jsonObject = JSONObject.parseObject(res);
        String code = jsonObject.getString("code");
        if (HttpConstant.SUCCESS_RES_CODE.equals(code)){
            //算法启动成功------指定版本算法已开启成功，其余该服务器其余版本的算法状态需要设置为停止
            algorithmServerRelation.setAlgorithmState(runningState);
            algorithmServerRelation.setIsAvailable(AvailableEnums.ENABLE.getType());
            iAlgorithmServerRelationService.updateById(algorithmServerRelation);
            //将该服务器上的其余版本都设置为关闭状态
            iAlgorithmServerRelationService.setAlgorithmStopStatus(AlgorithmStateEnums.NOT_START.getType(),serverPO.getId(),algorithmServerRelation.getFunctionId(),algorithmServerRelation.getAlgorithmId());

            return CommonResponse.ok("操作完成"+jsonObject.getString("message"));

        }else {
            //算法异常
            algorithmServerRelation.setAlgorithmState(AlgorithmStateEnums.ISException.getType());
            algorithmServerRelation.setIsAvailable(AvailableEnums.NOT_ENABLE.getType());

            iAlgorithmServerRelationService.updateById(algorithmServerRelation);

            //将该服务器上的其余版本都设置为关闭状态
            iAlgorithmServerRelationService.setAlgorithmStopStatus(AlgorithmStateEnums.NOT_START.getType(),serverPO.getId(),algorithmServerRelation.getFunctionId(),null);

            return  CommonResponse.error("操作失败: "+jsonObject.getString("message"));
        }

    }

    @Override
    public CommonResponse updateAlgorithmInfo(AlgorithmPackageStatus algorithmPackageStatus) {
        /**
         * 1.获取到算法id，功能id。
         * 2.查询当前算法是否在运行，若在运行，则不允许修改。
         */
        //算法id
        Integer algorithmID = algorithmPackageStatus.getId();
        //功能id
        String functionId = algorithmPackageStatus.getFunctionId();

        List<AlgorithmServerRelation> algorithmServerRelationList = iAlgorithmServerRelationService
                .list(new QueryWrapper<AlgorithmServerRelation>().eq("function_id", functionId).eq("algorithm_id", algorithmID)
                        .eq("algorithm_state",AlgorithmStateEnums.START.getType()));
        if (!CollectionUtils.isEmpty(algorithmServerRelationList)){
            throw new RuntimeException("当前算法正在运行，请停止后重新修改");
        }

        updateById(algorithmPackageStatus);

        return CommonResponse.ok("更新成功");
    }

    @Override
    public CommonResponse getAlgorithmInfoById(String algorithmId) {

        AlgorithmPackageStatus packageStatus = getById(algorithmId);

        return CommonResponse.ok(packageStatus);
    }

    @Override
    public CommonResponse getFunctionInfo(String functionId) {

        FunctionPO functionPO = functionService.getById(functionId);

        return CommonResponse.ok(functionPO);
    }

    /**
     * 将前端入参变化为存入DB的DTO
     * @param algorithmPackageParam 页面参数
     * @param algorithmFilePath 算法文件存储路径
     * @return
     */
    public AlgorithmPackageStatus convertToAlgorithmDTO( AlgorithmPackageParam algorithmPackageParam, String algorithmFilePath){

        AlgorithmPackageStatus algorithmPackageStatus = new AlgorithmPackageStatus();
        BeanUtils.copyProperties(algorithmPackageParam,algorithmPackageStatus);
        //功能id
        algorithmPackageStatus.setFunctionId(algorithmPackageParam.getAlgorithmId());
        //状态先设为0，后期可能废除该字段
        algorithmPackageStatus.setStatus("0");
        //算法文件存储路径
        algorithmPackageStatus.setPackagePath(algorithmFilePath);
        algorithmPackageStatus.setCreateTime(LocalDateTime.now());
        algorithmPackageStatus.setUpdateTime(LocalDateTime.now());
        algorithmPackageStatus.setUpdateUser(SecurityUtils.getLoginUserName());
        algorithmPackageStatus.setUpdateUser(SecurityUtils.getLoginUserName());
        return algorithmPackageStatus;
    }

}
